<template>
  <div class="img_code-outer" v-show="modelValue" :style="`font-size: ${size}px;`">
    <p @click="hide"></p>
    <div>
      <header>
        <span>安全验证</span>
        <img :class="{runing:runing}" :src="ico_refresh" @click="refresh"/>
      </header>
      <div ref="map" @click="click">
        <img :src="img.map"/>
        <p v-for="(p,i) in points" :style="'left:'+(p.left*100)+'%; top:'+(p.top*100)+'%;background: url('+ico_point+');'" ><span>{{i+1}}</span></p>
      </div>
      <footer>
        <span>点击图片中的:</span>
        <img :src="img.target"/>
      </footer>
    </div>
  </div>
</template>

<script>
export default {
  name: "img_code",
  props: {
    /**
     * 为了移动端适配，可以自定义图片验证码DOM的尺寸，单位(px)，显示的dom宽度为：6*size，默认：100
     */
    size: {
      type: Number,
      default: 100,
    },
    /**
     * 返回验证码图片地址(格式：{map:点击背景图, target:表示点击目标的图片})的方法，异步情况返回 Promise
     */
    img_data: {
      type: Function,
      required: true
    },
    modelValue: Boolean,
  },
  emits: ['update:modelValue','click:point'],
  data(){
    return {
      ico_refresh: '',
      ico_point: '',
      runing: false,
      img: {map: '', target:''},
      points: [],
    }
  },
  methods: {
    click(e){
      let dom = this.$refs['map'];
      let exy = {x: e.clientX, y: e.clientY};
      let r =  dom.getBoundingClientRect();
      let dxy = {x:r.left ,y:r.top};
      let xy = {x: exy.x-dxy.x, y: exy.y-dxy.y};

      let w = dom.offsetWidth;
      let h = dom.offsetHeight;
      this.points.push({left: xy.x/w, top: xy.y/h});
      this.$emit('click:point', this.points);
    },
    /**
     * 刷新图片验证码，会重新调用 img_data 方法
     */
    refresh(){
      if(this.runing) return;
      this.runing = true;
      this.points=[];
      Promise.resolve(this.img_data()).then((data)=>{
        if (!data?.map || !data?.target) throw '参数错误';
        this.img.map = data.map;
        this.img.target = data.target;
        this.runing = false;
      }).catch(()=>{ this.runing = false; })
    },
  },
  mounted() {
    this.refresh();
  }
}
</script>

<style scoped>
@keyframes turn_img_code-outer{
  0%{transform: rotate(0deg);}
  100%{transform: rotate(360deg);}
}
.img_code-outer{position: fixed;color: #000;left: 0;top: 0;width: 100%;height: 100%;z-index: 999999;display: flex;justify-content: center;align-items: center;}
.img_code-outer *{box-sizing: border-box;margin: 0;padding: 0;-webkit-tap-highlight-color: rgba(0,0,0,0);}
.img_code-outer>p{position: absolute;left: 0;top: 0;width: 100%;height: 100%;z-index: 0;}
.img_code-outer>div{width: 6em;background: #fff;padding: 0.4em;border-radius: 0.08em;position: relative;}
.img_code-outer>div>header{display: flex;width: 100%;height: 0.6em;font-weight: bold;position: relative;justify-content: center;align-items: center;}
.img_code-outer>div>header>span{font-size: 0.32em;}
.img_code-outer>div>header>img{position: absolute;width: 0.4em;right: 0.1em;top: 0.1em;}
.img_code-outer>div>header>img.runing{animation: turn_img_code-outer 1s linear 0s infinite;}
.img_code-outer>div>div{width: 100%;background: #e7e7e7;position: relative;line-height: 0;}
.img_code-outer>div>div>img{position: relative;width: 100%;z-index: 0;}
.img_code-outer>div>div>p{position: absolute;z-index: 2;width: 0.54em;height: 0.64em;text-align: center;transform: translate(-50%, -100%);background-size: 100%;}
.img_code-outer>div>div>p>span{font-size: 0.3em;line-height: 2;color: #fff;}
.img_code-outer>div>footer{height: 0.6em;margin-top: 0.1em;display: flex;justify-content: space-between;align-items: center;}
.img_code-outer>div>footer>span{font-size: 0.28em;text-align: right;flex-basis: 100%;}
.img_code-outer>div>footer>img{width: auto;height: 100%;margin-left: 0.2em;}
</style>